﻿using System;
using SharpDX.DirectInput;
using SharpDX;
using SharpDX.Windows;
using System.Collections.Generic;

namespace DX11Engine
{
    /// <summary>Handles DirectInput.</summary>
    public class Jinput
    {
        // Internal device collections:
        private DirectInput _dInput = new DirectInput();
        private Keyboard _kybrd;
        private Dictionary<Key, bool> _isPressed = new Dictionary<Key,bool>();
        private Mouse _mouse;

        /// <summary>List of dictionary with a bool value represiting if the key is currently being pressed.</summary>
        public Dictionary<Key, bool> Keys
        {
            get {
                _kybrd.Poll(); // Check for data
                KeyboardUpdate[] kyrdSt = _kybrd.GetBufferedData(); // Get data
                for (int i = 0; i < kyrdSt.Length; i++)
                {
                    // If a existing key, update the state, otherwise add the new key:
                    if (_isPressed.ContainsKey(kyrdSt[i].Key))
                    { _isPressed[kyrdSt[i].Key] = kyrdSt[i].IsPressed; }
                    else { _isPressed.Add(kyrdSt[i].Key, kyrdSt[i].IsPressed); }
                }
                return _isPressed;
            }
        }

        /// <summary>Contains relative mouse update.</summary>
        public MouseState Mouse
        {
            get
            {
                _mouse.Poll(); // Check for data
                MouseUpdate[] msUpdt = _mouse.GetBufferedData(); // Get data
                
                // Create a MouseState class that will contains the mouse current state:
                MouseState ms = new MouseState();

                // Check for data:
                if (msUpdt.Length > 0)
                {
                    // Go through buffer:
                    for (int i = 0; i < msUpdt.Length; i++)
                    {
                        // Update MouseState accordingly:
                        switch (msUpdt[i].Offset)
                        {
                            case MouseOffset.X: { ms.X += msUpdt[i].Value; break; }
                            case MouseOffset.Y: { ms.Y += msUpdt[i].Value; break; }
                            case MouseOffset.Z: { ms.Z += msUpdt[i].Value; break; }
                            case MouseOffset.Buttons0: { ms.Buttons[0] = Convert.ToBoolean(msUpdt[i].Value); break; }
                            case MouseOffset.Buttons1: { ms.Buttons[1] = Convert.ToBoolean(msUpdt[i].Value); break; }
                            case MouseOffset.Buttons2: { ms.Buttons[2] = Convert.ToBoolean(msUpdt[i].Value); break; }
                            case MouseOffset.Buttons3: { ms.Buttons[3] = Convert.ToBoolean(msUpdt[i].Value); break; }
                            case MouseOffset.Buttons4: { ms.Buttons[4] = Convert.ToBoolean(msUpdt[i].Value); break; }
                            case MouseOffset.Buttons5: { ms.Buttons[5] = Convert.ToBoolean(msUpdt[i].Value); break; }
                            case MouseOffset.Buttons6: { ms.Buttons[6] = Convert.ToBoolean(msUpdt[i].Value); break; }
                            case MouseOffset.Buttons7: { ms.Buttons[7] = Convert.ToBoolean(msUpdt[i].Value); break; }
                        }
                    }
                }

                // Return generated MouseState:
                return ms;
            }
        }

        /// <summary>Necessary in order to set up and initialize keyboard & mouse input. </summary>
        /// <param name="frm">Handle to the form used for rendering D3D graphics</param>
        public Jinput(RenderForm frm)
        {
            // Set up keyboard and begin acquiring input:
            _kybrd = new Keyboard(_dInput);
            _kybrd.SetCooperativeLevel(frm, CooperativeLevel.NonExclusive | CooperativeLevel.Background);
            _kybrd.Properties.BufferSize = 128;
            _kybrd.Acquire();

            // Set up mouse and begin acquiring input:
            _mouse = new Mouse(_dInput);
            _mouse.Properties.BufferSize = 64;
            _mouse.Properties.AxisMode = DeviceAxisMode.Relative;
            _mouse.Acquire();
        }

        /// <summary>Releases all resources used by the DirectInput class.</summary>
        public void Dispose()
        {
            if (_kybrd != null) {
                _kybrd.Unacquire();
                _kybrd.Dispose();
            }
            if (_mouse != null) {
                _mouse.Unacquire();
                _mouse.Dispose();
            }
            if (_dInput != null) 
            { _dInput.Dispose();}
        }
    }
}
